/* eslint-disable @typescript-eslint/no-explicit-any */
import { Settings } from "store/Settings";
import { Payload } from "../../structures/dto/Payload";
import { Client } from "../Client";
import { handlers } from "./handlers/index";


// Connecting  = 0,
// Open        = 1,
// Closing     = 2,
// Closed      = 3,
// Error       = 4

export enum SocketStatus {
    CONNECTING,
    OPEN,
    CLOSING,
    CLOSED,
    ERROR
}

export class SocketManager {
    private isBackground = false;
    private socket!: Qml.WebSocket
    private counter: number = 0

    constructor(private client: Client) {
        this.socket = Qt.createQmlObject<Qml.WebSocket>("import QtWebSockets 1.0; WebSocket { }", window);
        console.log("created socket");
        this.socket.textMessageReceived.connect(this.handleMessage);
        this.socket.statusChanged.connect(status => {
            console.log("WS status cahnge  " + status + ", " + this.getStatusText(status));
            if (status > SocketStatus.CLOSING) {
                this.close()
                this.client.emit("disconnect", this.socket.errorString);
            }
        });
    }

    getStatusText(status: number) {
        switch (status) {
            case SocketStatus.CONNECTING:
                return qsTr("CONNECTING");
            case SocketStatus.OPEN:
                return qsTr("OPEN");
            case SocketStatus.CLOSING:
                return qsTr("CLOSING");
            case SocketStatus.CLOSED:
                return qsTr("CLOSED");
            case SocketStatus.ERROR:
                return qsTr("ERROR");
        }

    }

    connect() {
        this.socket.url = Settings.get("gatewayUrl") + "&d=" + new Date().getTime();
        this.socket.active = true;
        
        console.log("WS.connect:" + this.socket.active + ", " + this.socket.status+ ", " + this.getStatusText(this.socket.status))
    }

    close() {
        this.socket.active = false

        console.log("WS.close:" + this.socket.active + ", " + this.socket.status+ ", " + this.getStatusText(this.socket.status))
    }

    ready() {

    }

    send(payload: Payload) {
        const json = JSON.stringify(payload);

        this.client.emit("debug", "Sending payload: " + json);
        this.socket?.sendTextMessage(json);
    }

    setBackground(bg: boolean) {
        this.isBackground = bg;
    }

    private handleMessage = (msg: string) => {
        const tt = this.counter++;

        try {
            // this.client.emit("debug", "Received " + tt + " payload: " + msg);
            this.handlePayload(JSON.parse(msg));
        } catch (e : any) {
            this.client.emit("debug", "Received " + tt +" payload error: " + e.message + ' at ' + msg);
        }
    };

    /*
        Received unknown payload: {"t":null,"s":null,"op":7,"d":null}
    */

    private handlePayload(payload: Payload) {
        switch (payload.op) {
            case -1:

            case 0:
                this.client.heartbeat.setCount()
                if (payload.t && !handlers[payload.t]) {
                    this.client.emit("debug", "Received unknown payload: " + JSON.stringify(payload));
                } else {
                    payload.t && handlers[payload.t]?.(this.client, payload as any);
                }
                break;
            case 10:
                handlers.HELLO(this.client, payload as any);
                break;
            case 11:
                handlers.HEARTBEAT_ACK(this.client, payload);
                break;
            default:
                this.client.emit("debug", "Received unknown payload: " + JSON.stringify(payload));
        }
    }
}
